# -*- coding: utf-8 -*-
"""
账户管理表单类

包含账户余额、充值、交易记录相关的表单验证
支持多种支付方式和金额验证
"""

from decimal import Decimal, InvalidOperation
from flask_wtf import FlaskForm
from wtforms import StringField, DecimalField, SelectField, TextAreaField, HiddenField
from wtforms.validators import DataRequired, Length, NumberRange, ValidationError, Optional
from wtforms.widgets import NumberInput


class RechargeForm(FlaskForm):
    """账户充值表单"""

    amount = DecimalField(
        '充值金额',
        validators=[
            DataRequired(message='请输入充值金额'),
            NumberRange(min=1, max=10000, message='充值金额必须在1-10000元之间')
        ],
        widget=NumberInput(step='0.01', min='1', max='10000'),
        description='单次充值金额不能超过10000元'
    )

    payment_method = SelectField(
        '支付方式',
        choices=[
            ('alipay', '支付宝'),
            ('wechat', '微信支付'),
            ('unionpay', '银联支付'),
            ('balance', '账户余额')
        ],
        validators=[DataRequired(message='请选择支付方式')],
        description='选择您偏好的支付方式'
    )

    remarks = TextAreaField(
        '备注',
        validators=[Optional(), Length(max=200, message='备注不能超过200个字符')],
        description='可选，添加充值备注信息'
    )

    def validate_amount(self, field):
        """自定义金额验证"""
        try:
            # 转换为Decimal并检查精度
            amount = Decimal(str(field.data))
            if amount.as_tuple().exponent < -2:
                raise ValidationError('金额最多保留两位小数')

            # 检查最小金额
            if amount < Decimal('1'):
                raise ValidationError('最小充值金额为1元')

            # 检查最大金额
            if amount > Decimal('10000'):
                raise ValidationError('单次充值金额不能超过10000元')

        except (InvalidOperation, TypeError):
            raise ValidationError('请输入有效的金额格式')


class TransactionQueryForm(FlaskForm):
    """交易记录查询表单"""

    transaction_type = SelectField(
        '交易类型',
        choices=[
            ('', '全部类型'),
            ('recharge', '充值'),
            ('consume', '消费'),
            ('refund', '退款')
        ],
        validators=[Optional()],
        description='筛选特定类型的交易记录'
    )

    start_date = StringField(
        '开始日期',
        validators=[Optional()],
        render_kw={
            'type': 'date',
            'class': 'form-control'
        },
        description='查询起始日期'
    )

    end_date = StringField(
        '结束日期',
        validators=[Optional()],
        render_kw={
            'type': 'date',
            'class': 'form-control'
        },
        description='查询结束日期'
    )

    page_size = SelectField(
        '每页显示',
        choices=[
            ('10', '10条'),
            ('20', '20条'),
            ('50', '50条'),
            ('100', '100条')
        ],
        default='20',
        validators=[Optional()],
        description='设置每页显示的记录数量'
    )

    def validate_date_range(self):
        """验证日期范围"""
        if self.start_date.data and self.end_date.data:
            try:
                from datetime import datetime
                start = datetime.strptime(self.start_date.data, '%Y-%m-%d')
                end = datetime.strptime(self.end_date.data, '%Y-%m-%d')

                if start > end:
                    self.end_date.errors.append('结束日期不能早于开始日期')
                    return False

                # 限制查询范围不超过1年
                if (end - start).days > 365:
                    self.end_date.errors.append('查询范围不能超过1年')
                    return False

            except ValueError:
                self.start_date.errors.append('日期格式错误')
                return False

        return True


class BalanceOperationForm(FlaskForm):
    """余额操作表单（管理员用）"""

    operation_type = SelectField(
        '操作类型',
        choices=[
            ('adjust', '余额调整（设置为指定金额）'),
            ('recharge', '余额充值（在现有基础上增加）'),
            ('consume', '余额扣减（从现有余额中扣除）')
        ],
        validators=[DataRequired(message='请选择操作类型')],
        description='选择要执行的余额操作'
    )

    amount = DecimalField(
        '操作金额',
        validators=[
            DataRequired(message='请输入操作金额'),
            NumberRange(min=0.01, max=100000, message='金额必须在0.01-100000元之间')
        ],
        widget=NumberInput(step='0.01', min='0.01', max='100000'),
        description='调整：目标余额；充值/扣减：操作金额'
    )

    reason = TextAreaField(
        '操作原因',
        validators=[
            DataRequired(message='请输入操作原因'),
            Length(min=5, max=500, message='操作原因长度必须在5-500个字符之间')
        ],
        description='详细说明操作原因，此信息将记录在系统日志中'
    )

    user_id = HiddenField(
        validators=[DataRequired()]
    )

    def validate_amount(self, field):
        """验证操作金额"""
        try:
            amount = Decimal(str(field.data))
            if amount <= 0:
                raise ValidationError('操作金额必须大于0')

            # 检查小数位数
            if amount.as_tuple().exponent < -2:
                raise ValidationError('金额最多保留两位小数')

        except (InvalidOperation, TypeError):
            raise ValidationError('请输入有效的金额格式')


class RefundApplicationForm(FlaskForm):
    """退款申请表单"""

    transaction_id = HiddenField(
        validators=[DataRequired()]
    )

    refund_reason = SelectField(
        '退款原因',
        choices=[
            ('cancel_reservation', '取消预约'),
            ('duplicate_payment', '重复付款'),
            ('service_issue', '服务问题'),
            ('system_error', '系统错误'),
            ('other', '其他原因')
        ],
        validators=[DataRequired(message='请选择退款原因')],
        description='选择申请退款的主要原因'
    )

    refund_amount = DecimalField(
        '退款金额',
        validators=[
            DataRequired(message='请输入退款金额'),
            NumberRange(min=0.01, max=10000, message='退款金额必须在0.01-10000元之间')
        ],
        widget=NumberInput(step='0.01', min='0.01', max='10000'),
        description='申请退款的具体金额'
    )

    description = TextAreaField(
        '详细说明',
        validators=[
            DataRequired(message='请详细说明退款原因'),
            Length(min=10, max=500, message='说明内容长度必须在10-500个字符之间')
        ],
        description='详细描述退款的具体原因和情况'
    )

    contact_method = StringField(
        '联系方式',
        validators=[
            Optional(),
            Length(max=50, message='联系方式不能超过50个字符')
        ],
        description='可选，提供备用联系方式'
    )

    def validate_refund_amount(self, field):
        """验证退款金额"""
        try:
            amount = Decimal(str(field.data))

            # 检查小数位数
            if amount.as_tuple().exponent < -2:
                raise ValidationError('金额最多保留两位小数')

            if amount <= 0:
                raise ValidationError('退款金额必须大于0')

        except (InvalidOperation, TypeError):
            raise ValidationError('请输入有效的金额格式')


class AccountSettingsForm(FlaskForm):
    """账户设置表单"""

    auto_recharge = SelectField(
        '自动充值',
        choices=[
            ('disabled', '关闭'),
            ('enabled', '开启')
        ],
        default='disabled',
        validators=[Optional()],
        description='当余额低于阈值时自动充值'
    )

    recharge_threshold = DecimalField(
        '充值阈值',
        validators=[
            Optional(),
            NumberRange(min=0, max=1000, message='阈值必须在0-1000元之间')
        ],
        widget=NumberInput(step='0.01', min='0', max='1000'),
        description='触发自动充值的余额阈值'
    )

    auto_recharge_amount = DecimalField(
        '自动充值金额',
        validators=[
            Optional(),
            NumberRange(min=1, max=5000, message='自动充值金额必须在1-5000元之间')
        ],
        widget=NumberInput(step='0.01', min='1', max='5000'),
        description='每次自动充值的金额'
    )

    notification_enabled = SelectField(
        '消费通知',
        choices=[
            ('enabled', '开启'),
            ('disabled', '关闭')
        ],
        default='enabled',
        validators=[Optional()],
        description='是否接收账户消费通知'
    )

    monthly_limit = DecimalField(
        '月消费限额',
        validators=[
            Optional(),
            NumberRange(min=0, max=50000, message='月限额必须在0-50000元之间')
        ],
        widget=NumberInput(step='0.01', min='0', max='50000'),
        description='设置每月最大消费限额，0表示无限制'
    )

    def validate_auto_recharge_settings(self):
        """验证自动充值设置的一致性"""
        if self.auto_recharge.data == 'enabled':
            if not self.recharge_threshold.data:
                self.recharge_threshold.errors.append('开启自动充值时必须设置阈值')
                return False

            if not self.auto_recharge_amount.data:
                self.auto_recharge_amount.errors.append('开启自动充值时必须设置充值金额')
                return False

            if self.recharge_threshold.data >= self.auto_recharge_amount.data:
                self.auto_recharge_amount.errors.append('自动充值金额必须大于充值阈值')
                return False

        return True


class QuickRechargeForm(FlaskForm):
    """快速充值表单"""

    # 预设充值金额选项
    quick_amount = SelectField(
        '快速充值',
        choices=[
            ('', '自定义金额'),
            ('50', '50元'),
            ('100', '100元'),
            ('200', '200元'),
            ('500', '500元'),
            ('1000', '1000元')
        ],
        validators=[Optional()],
        description='选择常用充值金额或自定义'
    )

    custom_amount = DecimalField(
        '自定义金额',
        validators=[
            Optional(),
            NumberRange(min=1, max=10000, message='金额必须在1-10000元之间')
        ],
        widget=NumberInput(step='0.01', min='1', max='10000'),
        description='输入自定义充值金额'
    )

    payment_method = SelectField(
        '支付方式',
        choices=[
            ('alipay', '支付宝'),
            ('wechat', '微信支付'),
            ('unionpay', '银联支付')
        ],
        validators=[DataRequired(message='请选择支付方式')],
        description='选择支付方式'
    )

    def get_final_amount(self):
        """获取最终充值金额"""
        if self.quick_amount.data and self.quick_amount.data != '':
            return Decimal(self.quick_amount.data)
        elif self.custom_amount.data:
            return self.custom_amount.data
        else:
            return None

    def validate(self):
        """表单整体验证"""
        if not super().validate():
            return False

        # 必须选择金额（快速选择或自定义）
        if not self.quick_amount.data and not self.custom_amount.data:
            self.custom_amount.errors.append('请选择或输入充值金额')
            return False

        # 如果同时填写了快速金额和自定义金额，提示用户
        if self.quick_amount.data and self.custom_amount.data:
            self.custom_amount.errors.append('请只选择一种金额输入方式')
            return False

        return True